﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Xml.Linq;
using System.IO;
using System.Runtime.InteropServices;

namespace UpdateFile2
{
    public partial class MainForm : Form
    {
        //[DllImport("Kernel32.dll", SetLastError = true)]
        //public static extern bool AllocConsole();
        //[DllImport("Kernel32.dll", SetLastError = true)]
        //public static extern bool FreeConsole();

        XDocument m_doc = null;
        XElement m_root = null, m_version = null, m_description = null, m_filelist = null;
        ServiceReference.UpdateServiceClient m_update = null;
        string m_dir = null;
        string m_ownerfilename = "";

        public MainForm()
        {
            InitializeComponent();
            DoubleBuffered = true;
            //AllocConsole();
            string[] args = Environment.GetCommandLineArgs();
            if (args.Length == 3)
            {
                try
                {
                    m_ownerfilename = args[2];
                    string result = InitCheckUpdate(args[1]);
                    switch (result)
                    {
                        case "需要更新":
                            {
                                Console.Out.WriteLine("Updating");
                                Console.Out.Flush();
                                timer1.Enabled = true;
                            }
                            break;
                        case "已是最新版本":
                            {
                                Console.Out.WriteLine("IsLatest");
                                Console.Out.Flush();
                                Environment.Exit(0);
                            }
                            break;
                        default:
                            Console.WriteLine(result);
                            Environment.Exit(0);
                            break;
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    Environment.Exit(0);
                }
                //FreeConsole();
                
            }
            else
            {
                //FreeConsole();
                Environment.Exit(1);
            }
        }

        private void AddStr(string str)
        {
            listBox1.Items.Add(str);
            Application.DoEvents();
        }

        private string InitCheckUpdate(string NameSpace)
        {
            listBox1.Items.Clear();
            AddStr("正在获取更新...");
            m_update = new ServiceReference.UpdateServiceClient();
            //m_update.Endpoint.Address = new System.ServiceModel.EndpointAddress("http://127.0.0.1:12772/UpdateService.svc");
            string xml = m_update.GetUpdateXml(NameSpace);
            if (xml.Length == 0)
            {
                return "无法获取更新";
            }
            listBox1.Items.Clear();
            m_doc = XDocument.Parse(xml);
            m_root = m_doc.Root;
            m_version = m_root.Element("version");
            AddStr("更新版本：V"+m_version.Value);
            m_description = m_root.Element("description");
            AddStr("更新时间：" + m_root.Element("updatetime").Value);
            AddStr("更新说明："+m_description.Value);
            m_filelist = m_root.Element("filelist");
            m_dir = m_filelist.Attribute("sourcepath").Value;

            IEnumerable<XElement> elements = m_filelist.Elements();
            int emcount = 0, ignorecount = 0;
            foreach (XElement em in elements)
            {
                emcount++;
                string destinationpath = em.Attribute("destinationpath").Value;
                string filename = em.Attribute("filename").Value;
                string filepath = AppDomain.CurrentDomain.BaseDirectory;
                if (destinationpath != ".")
                {
                    string tempdir = filepath + destinationpath;
                    if (!Directory.Exists(tempdir))
                        Directory.CreateDirectory(tempdir);

                    filename = destinationpath + "\\" + filename;
                    filepath += filename;
                }
                else
                    filepath += filename;

                int filesize = Convert.ToInt32(em.Attribute("filesize").Value);
                string md5 = em.Attribute("md5").Value;

                string localfilepath = AppDomain.CurrentDomain.BaseDirectory + filename;
                if (File.Exists(localfilepath))
                {
                    if (MD5CalcHelper.MD5File(localfilepath) == md5)
                        ignorecount++;
                }
            }

            return ignorecount == emcount ? "已是最新版本" : "需要更新";
        }

        private void UpdateFile()
        {
            IEnumerable<XElement> elements = m_filelist.Elements();
            foreach (XElement em in elements)
            {
                string destinationpath = em.Attribute("destinationpath").Value;
                string filename = em.Attribute("filename").Value;
                string filepath = AppDomain.CurrentDomain.BaseDirectory;
                if (destinationpath != ".")
                {
                    filename = destinationpath + "\\" + filename;
                    if (!Directory.Exists(filepath))
                        Directory.CreateDirectory(filepath);
                    filepath += filename;
                }
                else
                    filepath += filename;

                string url = m_dir + "\\" + filename;
                int filesize = Convert.ToInt32(em.Attribute("filesize").Value);
                string md5 = em.Attribute("md5").Value;

                string localfilepath = AppDomain.CurrentDomain.BaseDirectory + filename;
                if (File.Exists(localfilepath))
                {
                    if (MD5CalcHelper.MD5File(localfilepath) == md5)
                        continue;
                    else
                    {
                        string olddir = AppDomain.CurrentDomain.BaseDirectory + "olddata";
                        if (!Directory.Exists(olddir))
                            Directory.CreateDirectory(olddir);
                        string oldfilename = olddir + "\\" + Path.GetFileName(localfilepath);
                        if (File.Exists(oldfilename))
                            File.Delete(oldfilename);
                        File.Move(localfilepath, oldfilename);
                    }
                }

                double maxpos = filesize;
                progressBar1.Maximum = filesize;
                progressBar1.Value = progressBar1.Minimum;

                int index = listBox1.Items.Add(string.Format("{0} {1:f2}%", filename, 0));

                using (FileStream fs = File.Create(filepath))
                {
                    int pos = 0, BUFFER_SIZE = 8192;
                    do
                    {
                        byte[] buffer = m_update.GetUpdateFileData(url, pos, BUFFER_SIZE);
                        fs.Write(buffer, 0, buffer.Length);
                        pos += buffer.Length;
                        string posvalue = string.Format("{0:f2}", (pos / maxpos) * 100);
                        if (posvalue.Substring(posvalue.Length - 2) == "00")
                        {
                            posvalue = posvalue.Replace(".00", "");
                            listBox1.Items[index] = string.Format("更新文件：{0} {1}%", filename, posvalue);
                            progressBar1.Value = pos;
                        }
                        Application.DoEvents();
                        if (buffer.Length != BUFFER_SIZE)
                        {
                            break;
                        }
                    } while (true);
                }
            }
            AddStr("更新完毕！");
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            timer1.Enabled = false;
            UpdateFile();
            AddStr("即将重新启动主程序。");
            timer2.Enabled = true;
        }

        private void timer2_Tick(object sender, EventArgs e)
        {
            timer2.Enabled = false;
            System.Diagnostics.Process.Start(m_ownerfilename);
            Close();
        }
    }
}
